package com.jdrx.ocp.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jdrx.ocp.beans.commons.SysConstant;
import com.jdrx.ocp.beans.constans.*;
import com.jdrx.ocp.beans.dto.role.*;
import com.jdrx.ocp.beans.entity.RolePO;
import com.jdrx.ocp.beans.entity.RoleResourcePO;
import com.jdrx.ocp.beans.entity.UserPO;
import com.jdrx.ocp.beans.entity.UserRolePO;
import com.jdrx.ocp.beans.entity.util.ExceptionMessageFilter;
import com.jdrx.ocp.beans.event.NoticesEvent;
import com.jdrx.ocp.beans.vo.QueryRoleResourceVO;
import com.jdrx.ocp.beans.vo.QueryRoleVO;
import com.jdrx.ocp.beans.vo.RoleForUserVO;
import com.jdrx.ocp.dao.RoleDAO;
import com.jdrx.ocp.dao.RoleResourceDAO;
import com.jdrx.ocp.dao.UserRoleDAO;
import com.jdrx.ocp.utils.Convertor;
import com.jdrx.platform.commons.rest.beans.dto.IdDTO;
import com.jdrx.platform.commons.rest.exception.BizException;
import com.jdrx.platform.jdbc.beans.vo.PageVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 角色管理
 *
 * @Author: Huangxg
 * @Date: 2018/11/20 13:36
 */
@Service
public class RoleService {

    private static final Logger logger = LoggerFactory.getLogger(RoleService.class);

    @Autowired
    RoleDAO roleDAO;
    @Autowired
    RoleResourceDAO roleResourceDAO;
    @Autowired
    UserRoleDAO userRoleDAO;
    @Autowired
    NoticeEventService noticeEventService;
    @Autowired
    UserService userService;
    @Autowired
    ResourceService resourceService;

    /**
     * 查询参数处理
     *
     * @param queryRoleDTO
     * @return
     */
    private Map<String, Object> initQueryRole(QueryRoleDTO queryRoleDTO) {
        Map<String, Object> map = new HashMap<String, Object>(5);
        map.put("name", Optional.ofNullable(queryRoleDTO.getName()).orElse(null));
        map.put("delFlag", EDeleteFlag.NORMAL.getKey());
        //默认直接取用户的角色 , 如果是取运维的角色需要传递指定参数[roleType = 2]
        map.put("roleType", Optional.ofNullable(queryRoleDTO.getRoleType()).orElse(ERoleType.USER.getKey()));
        map.put("deptPath", queryRoleDTO.getDeptPath());
        return map;
    }

    /**
     * 带分布的角色数据查询
     *
     * @param queryRoleDTO
     * @return
     * @throws BizException
     */
    public PageVO<RoleForUserVO> queryRoleByPage(QueryRoleDTO queryRoleDTO) throws BizException {
        try {
            Map<String, Object> queryMap = initQueryRole(queryRoleDTO);
            Page<RoleForUserVO> page = PageHelper.startPage(queryRoleDTO.getPageNum(), queryRoleDTO.getPageSize());
            roleDAO.listForUser(queryMap);
            PageVO<RoleForUserVO> pageVO = new PageVO<RoleForUserVO>(page);
            pageVO.setData(generateRoleData(page.getResult()));
            return pageVO;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("获取数据失败！");
        }
    }

    /**
     * 封装角色列表数据
     *
     * @param datas
     * @return
     * @throws BizException
     */
    private List<RoleForUserVO> generateRoleData(List<RoleForUserVO> datas) throws BizException {
        if (CollectionUtils.isEmpty(datas)) {
            return datas;
        }
        try {
            for (RoleForUserVO vo : datas) {
                Map<String, Object> map = new HashMap<>();
                map.put("roleId", vo.getId());
                vo.setResourceAllIds(Convertor.converToReourceIds(roleResourceDAO.listBy(map)));
            }
            return datas;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("获取数据失败！");
        }
    }

    /**
     * 角色数据返回结构体
     *
     * @param datas
     * @return
     * @throws BizException
     */
    private List<QueryRoleVO> generateQueryRoleVO(List<RolePO> datas) throws BizException {
        try {
            List<QueryRoleVO> voList = new ArrayList<QueryRoleVO>();
            if (CollectionUtils.isEmpty(datas)) {
                return voList;
            }
            QueryRoleVO vo = null;
            for (RolePO t : datas) {
                vo = new QueryRoleVO();
                BeanUtils.copyProperties(t, vo);
                voList.add(vo);
            }
            return voList;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("获取数据失败！");
        }
    }

    /**
     * 添加角色
     *
     * @param createRoleDTO
     * @return
     * @throws BizException
     */
    @Transactional(rollbackFor = Exception.class)
    public int createRole(CreateRoleDTO createRoleDTO, Integer uId) throws BizException {
        try {
            Map<String, Object> qmap = new HashMap<>(3);
            qmap.put("name", createRoleDTO.getName());
            qmap.put("delFlag", EDeleteFlag.NORMAL.getKey());
            qmap.put("roleType", Optional.ofNullable(createRoleDTO.getRoleType()).orElse(ERoleType.USER.getKey()));
            RolePO existRole = roleDAO.roleByName(qmap);
            if (existRole != null && existRole.getDelFlag().equals(EDeleteFlag.NORMAL.getKey())) {
                throw new BizException("角色已存在");
            }
            RolePO rolePO = new RolePO();
            BeanUtils.copyProperties(createRoleDTO, rolePO);
            Date nowTime = new Date();
            rolePO.setCreateAt(nowTime);
            rolePO.setCreateBy(uId);
            rolePO.setDelFlag(EDeleteFlag.NORMAL.getKey().toString());
            rolePO.setUpdateAt(nowTime);
            rolePO.setUpdateBy(uId);
            rolePO.setResourceIds(createRoleDTO.getResourceIds());
            rolePO.setRemark(createRoleDTO.getName());
            rolePO.setIdentifier("");
            int num = roleDAO.insert(rolePO);

            if (num <= 0) {
                throw new BizException("创建角色失败");
            }
            //noticeEventService.publishEvent(new NoticesEvent(this, EventEnum.ROLE, EventActionEnum.CREATE));
            //给角色授权
            RoleResourceDTO resourceDTO = new RoleResourceDTO();
            resourceDTO.setRoleId(rolePO.getId().intValue());
            //获取所有资源节点，包含子节点的父级
            List<Integer> ids = Convertor.converToInteger(createRoleDTO.getResourceIds());
            List<Integer> allIds = resourceService.getResourceIdsAndParentIds(ids);
            resourceDTO.setRoleResource(allIds);
            awardedRoleResource(resourceDTO);
            return num;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException(ExceptionMessageFilter.filter(e.getMessage()));
        }
    }

    /**
     * 更新角色数据
     *
     * @param updateRoleDTO
     * @return
     * @throws BizException
     */
    @Transactional(rollbackFor = Exception.class)
    public int updateRole(UpdateRoleDTO updateRoleDTO, Integer uId) throws BizException {
        try {
            RolePO oldRolePO = roleDAO.getById(updateRoleDTO.getId());
            if (null == oldRolePO) {
                throw new BizException("修改对象不存在");
            }
            if (updateRoleDTO.getName() != null) {
                Map<String, Object> existMap = new HashMap<>(3);
                existMap.put("name", updateRoleDTO.getName());
                existMap.put("id", updateRoleDTO.getId());
                existMap.put("roleType", Optional.ofNullable(oldRolePO.getRoleType()).orElse(ERoleType.USER.getKey()));
                RolePO existRole = roleDAO.roleExistByName(existMap);
                if (existRole != null) {
                    throw new BizException("角色已存在");
                }
            }
            RolePO newRolePo = new RolePO();
            BeanUtils.copyProperties(updateRoleDTO, newRolePo);
            newRolePo.setUpdateBy(uId);
            newRolePo.setResourceIds(updateRoleDTO.getResourceIds());
            newRolePo.setUpdateAt(new Date());
            int num = roleDAO.update(newRolePo);

            if (num <= 0) {
                throw new BizException("修改角色失败");
            }
            noticeEventService.publishEvent(new NoticesEvent(this, EventEnum.DEPT, EventActionEnum.MODIDY));
            //给角色授权
            RoleResourceDTO resourceDTO = new RoleResourceDTO();
            resourceDTO.setRoleId(updateRoleDTO.getId().intValue());
            //获取所有资源节点，包含子节点的父级
            List<Integer> ids = Convertor.converToInteger(updateRoleDTO.getResourceIds());
            List<Integer> allIds = resourceService.getResourceIdsAndParentIds(ids);
            resourceDTO.setRoleResource(allIds);
            awardedRoleResource(resourceDTO);
            return num;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException(ExceptionMessageFilter.filter(e.getMessage()));
        }
    }

    /**
     * 删除角色，标记删除
     *
     * @param idDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public String deleteRole(IdDTO idDTO, Integer uId) throws BizException {
        RolePO rolePO = roleDAO.getById(Long.valueOf(idDTO.getId().toString()));
        if (null == rolePO) {
            throw new BizException("操作对象不存在");
        }

        //2019-3-25:bug修复：存在用户使用该角色时，该角色不能被删除
        UserRolePO po = new UserRolePO();
        po.setRoleId(Integer.valueOf(String.valueOf(idDTO.getId())));
        List<UserRolePO> rolePOs = userRoleDAO.listByCondition(po);
        if (!CollectionUtils.isEmpty(rolePOs)) {
            throw new BizException("该角色已被用户使用，不能被删除");
        }

        RolePO delRole = new RolePO();
        delRole.setId(Long.valueOf(idDTO.getId().toString()));
        delRole.setDelFlag(EDeleteFlag.DELETE.getKey());
        int num = roleDAO.update(delRole);
        if (num > 0) {
            noticeEventService.publishEvent(new NoticesEvent(this, EventEnum.DEPT, EventActionEnum.DELETE));
            //同步删除用户对应的角色
            deleteUserRoleByRoleId(delRole.getId());
            return rolePO.getName();
        }
        throw new BizException("执行角色删除失败");
    }

    /**
     * 根据角色删除用户角色关系
     *
     * @param roleId
     * @return
     * @throws BizException
     */
    public int deleteUserRoleByRoleId(Long roleId) throws BizException {
        return userRoleDAO.deleteByRoleId(roleId);
    }

    /**
     * 用户角色资源分配
     *
     * @param roleResourceDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean awardedRoleResource(RoleResourceDTO roleResourceDTO) throws BizException {
        try {
            //删除之前的数据
            deleteRoleResource(roleResourceDTO.getRoleId());
            //生成用户角色资源数据
            List<RoleResourcePO> list = generateRoleResource(roleResourceDTO);
            //批量写入数据
            if (list != null && list.size() > 0) {
                roleResourceDAO.insertBatch(list);
            }
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("处理数据失败！");
        }
    }

    /**
     * 生成用户角色资源数据
     *
     * @param roleResourceDTO
     * @return
     */
    private List<RoleResourcePO> generateRoleResource(RoleResourceDTO roleResourceDTO) {
        List<Integer> resourceIds = roleResourceDTO.getRoleResource();
        List<RoleResourcePO> list = new ArrayList<RoleResourcePO>();
        RoleResourcePO roleResourcePO = null;
        for (int resId : resourceIds) {
            roleResourcePO = new RoleResourcePO();
            roleResourcePO.setResourceId(resId);
            roleResourcePO.setRoleId(roleResourceDTO.getRoleId());
            list.add(roleResourcePO);
        }
        return list;
    }

    /**
     * 删除角色资源
     *
     * @param roleId
     * @throws BizException
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteRoleResource(Integer roleId) throws BizException {
        try {
            roleResourceDAO.deleteByRoleId(roleId);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("删除数据失败！");
        }
    }

    /**
     * 查询角色所拥有的资源
     *
     * @param roleId
     * @return
     * @throws BizException
     */
    public List<QueryRoleResourceVO> queryRoleResource(Integer roleId) throws BizException {
        try {
            return roleResourceDAO.listByRole(roleId);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("获取数据失败！");
        }
    }

    /**
     * 查询所有角色
     *
     * @param queryRoleDTO
     * @return
     * @throws BizException
     */
    public List<RoleForUserVO> queryRoles(QueryRoleNoPageDTO queryRoleDTO) throws BizException {
        try {
            QueryRoleDTO queryRoleDTO1 = new QueryRoleDTO();
            queryRoleDTO1.setName(queryRoleDTO.getName());
            Map<String, Object> queryMap = initQueryRole(queryRoleDTO1);
            return roleDAO.listForUser(queryMap);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("获取数据失败！");
        }
    }

    /**
     * 查询用户所拥有的角色
     *
     * @param queryRoleDTO
     * @return
     * @throws BizException
     */
    public List<RoleForUserVO> queryRoles(QueryRoleNoPageDTO queryRoleDTO, Integer userId) throws BizException {
        try {
            QueryRoleDTO queryRoleDTO1 = new QueryRoleDTO();
            queryRoleDTO1.setName(queryRoleDTO.getName());
            queryRoleDTO1.setRoleType(queryRoleDTO.getRoleType());
            queryRoleDTO1.setDeptPath(queryRoleDTO.getDeptPath());
            Map<String, Object> queryMap = initQueryRole(queryRoleDTO1);
            UserPO userPO = userService.getUserById(userId);
            if (userPO == null) {
                throw new BizException("登录用户信息异常！");
            } else if (!SysConstant.ADMIN_USER_NAME.equals(userPO.getName()) &&
                    !SysConstant.SYSTEM_USER_NAME.equals(userPO.getName()) &&
                    !EYesOrNo.YES.getKey().equals(userPO.getIsAdmin()) &&
                    !EYesOrNo.YES.getKey().equals(userPO.getIsSystem()) &&
                    !"2".equals(String.valueOf(queryRoleDTO.isLimit()))) {
                queryMap.put("userId", userId);
            }
            return roleDAO.listForUser(queryMap);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BizException("获取数据失败：" + e.getMessage());
        }
    }

    /**
     * 获取用户所拥有的角色
     *
     * @param userId
     * @return
     */
    public List<RolePO> findRoleByUserId(Long userId) throws BizException {
        if (userId == null) {
            throw new BizException("用户id为空");
        }
        return roleDAO.queryRoleByUserId(userId);
    }

}
